package com.letoken.platform.app.service.impl;

import java.math.BigDecimal;

import com.alibaba.fastjson.JSON;
import com.google.api.gax.rpc.ApiException;
import com.letoken.platform.app.async.AppUserLoginLogAsync;
import com.letoken.platform.app.service.AppUserWalletService;
import com.letoken.platform.app.service.LetokenUserAuthService;
import com.letoken.platform.pub.constant.LetokenUserConstant;
import com.letoken.platform.pub.constant.RedisKeyConstant;
import com.letoken.platform.pub.enums.LetokenApiResponseEnum;
import com.letoken.platform.pub.enums.LetokenBlockchainEnum;
import com.letoken.platform.pub.enums.LetokenTokenTypeEnum;
import com.letoken.platform.pub.exception.ApiServiceException;
import com.letoken.platform.pub.token.TokenUtil;
import com.letoken.platform.pub.util.BeanUtil;
import com.letoken.platform.pub.util.RandomUtil;
import com.letoken.platform.pub.util.SignUtil;
import com.letoken.platform.repo.app.dao.AppUserMapper;
import com.letoken.platform.repo.app.dto.ImUserLoginDto;
import com.letoken.platform.repo.app.manager.AppUserManager;
import com.letoken.platform.repo.app.manager.AppUserSessionManager;
import com.letoken.platform.repo.app.mq.manager.AppUserImMQManager;
import com.letoken.platform.repo.app.po.*;
import com.letoken.platform.repo.app.redis.*;
import com.letoken.platform.repo.app.req.user.AppUserLoginReq;
import com.letoken.platform.repo.app.res.user.AppUserLoginRes;
import com.letoken.platform.repo.utlis.LocalBlockUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author letokenlabs
 * @date 2022/11/14$
 */

@Service
@Log4j2
public class LetokenUserAuthServiceImpl implements LetokenUserAuthService {


//    @Resource
//    private AppUserAddressManager addressManager;
//
//    @Autowired
//    private AppUserAddressManager appUserAddressManager;


    @Autowired
    private AppUserSessionManager appUserSessionManager;


    @Autowired
    private AppUserLoginLogAsync appUserLoginLogAsync;

    @Autowired
    private AppUserWalletService appUserWalletService;

    @Resource
    private AppUserManager appUserManager;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private AppUserImMQManager appUserImMQManager;

    @Autowired
    private RabbitTemplate rabbitTemplate;
//    @Autowired
//    AppUserAddressMapper appUserAddressMapper;
    @Autowired
    AppUserMapper appUserMapper;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public AppUserLoginRes login(AppUserLoginReq req, String clientIP) {
        //todo 去掉了验证 AppUserSession,只验证了redis里的token
        log.info("login params [AppUserLoginReq={}, clientIP={}]", JSON.toJSONString(req), clientIP);
        String walletAddress = req.getWalletAddress();
        String sign = req.getSign();
        String message = req.getMessage();
        String blockchain = req.getBlockchain();
        AppUserLoginRes res = new AppUserLoginRes();

        //先校验钱包地址的合法性
        boolean check = false;
        if (LetokenBlockchainEnum.BSC.getValue().equalsIgnoreCase(blockchain)) {
            //ETH公链验签
            check = SignUtil.recoverSignature(message, sign, walletAddress);
        }
        if (!check) {
            log.info("login check signature verification failed");
            throw new ApiServiceException(LetokenApiResponseEnum.ERROR_APP_USER_003);
        }

        // 频率限制
        if(AppWalletRateLimitRedis.me().isLimited(walletAddress,"login", 1, 5L)) {
            throw new ApiServiceException(LetokenApiResponseEnum.ERROR_ADMIN_USER_033);
        }





        // app_user里面存的是用户自己提供的钱包地址
        AppUser appUser = appUserManager.queryByWalletAddres(walletAddress);
        String token = TokenUtil.generateToken();
        if (ObjectUtils.isEmpty(appUser)) {
            appUser = new AppUser();
            //用户信息为空，创建用户并绑定
            appUser.setWalletAddress(walletAddress);
            appUser.setAddressId(0);
            appUser.setInviterId(0);
            appUser.setInvitationCode(RandomUtil.getRandomNum());
            appUser.setCreateTime(LocalDateTime.now());
            // todo token不入库
            Integer flag = appUserManager.addUser(appUser);
//            AppUserAddress wallet = new AppUserAddress();
//            wallet.setWalletAddress(addr);
//            wallet.setIsUse(1);
//            wallet.setBlockchainType(1);
//            wallet.setCreateTime(LocalDateTime.now());
//            appUserAddressMapper.insert(wallet);
//            AppUser au = new AppUser();
//            au.setId(appUser.getId());
//            au.setAddressId(wallet.getId());
//            appUserMapper.updateById(au);

            if (flag > 0) {

                // 写入当前用户token
                AppUserTokenRedis.me().put(appUser.getId().toString(), token);

                appUser.setUserName(LetokenUserConstant.USER_ID_PREFIX + appUser.getId());
                appUser.updateById();
//                wallet.setUserId(appUser.getId());
//                wallet.updateById();
                LocalDateTime now = LocalDateTime.now();
                //将用户的平台钱包地址缓存到redis
//                AppWalletAddresRedis.me().put(String.valueOf(appUser.getId()), addr);
                AppUserTeam appUserTeam = new AppUserTeam();
                appUserTeam.setUserId(appUser.getId());
                appUserTeam.setEcoLevel(0);
                appUserTeam.setEcoValue(BigDecimal.ZERO);
                appUserTeam.setUserValue(BigDecimal.ZERO);
                appUserTeam.setTeamMember(0);
                appUserTeam.setTeamValue(0);
                appUserTeam.setUserAchievement(0);
                appUserTeam.setInviterId(0);
                appUserTeam.setCreateTime(now);
                appUserTeam.setUpdateTime(now);
                appUserTeam.setTeamSumValue(0);
                appUserTeam.insert();

                AppUserTeamPath appUserTeamPath = new AppUserTeamPath();
                appUserTeamPath.setUserId(appUser.getId());
                appUserTeamPath.setInvitePath("");
                appUserTeamPath.insert();


                // 新增到资产表里
                AppUserWallet letWallet = new AppUserWallet();
                letWallet.setUserId(appUser.getId());
                letWallet.setTokenId(LetokenTokenTypeEnum.LET.getId());
                letWallet.setAvailableBalance(BigDecimal.ZERO);
                letWallet.setFreezeBalance(BigDecimal.ZERO);
                letWallet.setReleasedBalance(BigDecimal.ZERO);
                letWallet.setUpdateTime(now);
                letWallet.setCreateTime(now);

                AppUserWallet usdtWallet = new AppUserWallet();
                usdtWallet.setUserId(appUser.getId());
                usdtWallet.setTokenId(LetokenTokenTypeEnum.USDT.getId());
                usdtWallet.setAvailableBalance(BigDecimal.ZERO);
                usdtWallet.setFreezeBalance(BigDecimal.ZERO);
                usdtWallet.setReleasedBalance(BigDecimal.ZERO);
                usdtWallet.setUpdateTime(now);
                usdtWallet.setCreateTime(now);

                AppUserWallet capWallet = new AppUserWallet();
                capWallet.setUserId(appUser.getId());
                capWallet.setTokenId(LetokenTokenTypeEnum.CAP.getId());
                capWallet.setAvailableBalance(BigDecimal.ZERO);
                capWallet.setFreezeBalance(BigDecimal.ZERO);
                capWallet.setReleasedBalance(BigDecimal.ZERO);
                capWallet.setUpdateTime(now);
                capWallet.setCreateTime(now);


                AppUserWallet capaWallet = new AppUserWallet();
                capaWallet.setUserId(appUser.getId());
                capaWallet.setTokenId(LetokenTokenTypeEnum.CAPA.getId());
                capaWallet.setAvailableBalance(BigDecimal.ZERO);
                capaWallet.setFreezeBalance(BigDecimal.ZERO);
                capaWallet.setReleasedBalance(BigDecimal.ZERO);
                capaWallet.setUpdateTime(now);
                capaWallet.setCreateTime(now);

                AppUserWallet lpWallet = new AppUserWallet();
                lpWallet.setUserId(appUser.getId());
                lpWallet.setTokenId(LetokenTokenTypeEnum.LP.getId());
                lpWallet.setAvailableBalance(BigDecimal.ZERO);
                lpWallet.setFreezeBalance(BigDecimal.ZERO);
                lpWallet.setReleasedBalance(BigDecimal.ZERO);
                lpWallet.setUpdateTime(now);
                lpWallet.setCreateTime(now);

                List<AppUserWallet> walletList = new ArrayList<>();
                walletList.add(letWallet);
                walletList.add(usdtWallet);
                walletList.add(capWallet);
                walletList.add(capaWallet);
                walletList.add(lpWallet);
                appUserWalletService.saveBatch(walletList);
            }
            else {
                throw new ApiServiceException(LetokenApiResponseEnum.ERROR_WALLET_WITHDRAW_015);
            }
        }
        else {
            //判断token是否存在缓存中，若存在，则踢出
            String queryToken = AppUserTokenRedis.me().getValue(appUser.getId().toString());// appUser.getToken();
            if (StringUtils.isNotBlank(queryToken)) {
                AppLoginTokenRedis.me().del(queryToken);
            }

            // 更新当前用户token
            AppUserTokenRedis.me().put(appUser.getId().toString(), token);
        }

        // token > 用户基础信息写入缓存
        AppLoginTokenRedis.me().put(token, appUser);

        // 用户登录将日志写入redis
        this.lPushRedisLoginLog(appUser, req, clientIP);

        //更新用户最后一次登录时间
        appUserManager.updateById(appUser);
        String deviceRes = req.getDeviceRes();
        Integer platform = null;
        if ("IOS".equals(deviceRes)) {
            platform = 1;
        } else if ("ANDROID".equals(deviceRes)) {
            platform = 2;
        }
        // 写入im服务器数据库
        try {
            this.imUserMQLogin(appUser.getId(), req.getDeviceId(), platform, token);
        } catch (Exception e) {
            log.error("im登录失败==========" + e);
        }

        res.setToken(token);
//        String address = addressManager.queryWalletByUserId(appUser.getId());
        LocalBlockUtils.AddressPo  po = LocalBlockUtils.obtainAddress(LocalBlockUtils.ObtainAddressDto.builder()
                .userId(appUser.getId())
                .coinId(LetokenTokenTypeEnum.USDT.getId())
                .build());
        res.setAppUserAddress(po.getAddr());
//        LocalBlockUtils.obtainAddress(LocalBlockUtils.ObtainAddressDto.builder()
//                .userId(appUser.getId())
//                .coinId(LetokenTokenTypeEnum.LET.getId())
//                .build());

        log.info("login return [ userName={}, userLoginPhoneSms={}]", JSON.toJSONString(res));
        return res;
    }

//    /**
//     * 注册session
//     *
//     * @param appUser
//     * @param req
//     * @param clientIP
//     * @return
//     */
//    private AppUserSession registerUserSession(AppUser appUser, AppUserLoginReq req, String clientIP) {
//        //先根据设备id和钱包用户id查询是否有注册session
//        AppUserSession appUserSession = appUserSessionManager.queryAppUserSessionById(appUser.getId());
//        String token = TokenUtil.generateToken();
//        //钱包地址未绑定账号
//        if (ObjectUtils.isEmpty(appUserSession)) {
//            appUserSession = new AppUserSession();
//            appUserSession.setUpdateTime(LocalDateTime.now());
//            appUserSession.setId(appUser.getId());
//            appUserSession.setToken(token);
//            appUserSession.setLoginIp(clientIP);
//            appUserSession.setActive(1);
//            appUserSession.setLoginidx(1); //登录计数
//            appUserSession.setCreateTime(LocalDateTime.now());
//            BeanUtil.quickCopy(req, appUserSession);
//            Integer flag = appUserSessionManager.addSession(appUserSession);
//            if (flag > 0) {
//                //更新缓存
//                AppLoginTokenRedis.me().put(token, appUser);
//            }
//        } else {
//            //先更新session
//            BeanUtil.quickCopy(req, appUserSession);
//            AppLoginTokenRedis.me().del(appUserSession.getToken());
//            appUserSession.setToken(token);
//            appUserSession.setUpdateTime(LocalDateTime.now());
//            appUserSessionManager.updateByIdAndDeviceId(appUserSession);
//            //更新缓存
//            AppLoginTokenRedis.me().put(token, appUser);
//        }
//        return appUserSession;
//    }

    /**
     * 用户登录将日志写入redis
     *
     * @param appUser
     * @param req
     * @param clientIP
     */
    private void lPushRedisLoginLog(AppUser appUser, AppUserLoginReq req, String clientIP) {
       // ListOperations<String, AppUserLoginLog> listOps = redisTemplate.opsForList();
        AppUserLoginLog appUserLoginLog = new AppUserLoginLog();
        BeanUtil.quickCopy(req, appUserLoginLog);
        appUserLoginLog.setAppUserId(appUser.getId());
        appUserLoginLog.setLoginIp(clientIP);
        appUserLoginLog.setCreateTime(LocalDateTime.now());
        appUserLoginLog.setType(1);
        appUserLoginLog.insert();
      //  listOps.leftPush(RedisKeyConstant.LETOKEN_APP_USER_LOGIN_LOG, appUserLoginLog);
    }

    private void imUserMQLogin(Integer userId, String clientId, Integer platform, String token) {
        ImUserLoginDto dto = new ImUserLoginDto();
        dto.setPlatform(platform);
        dto.setDeviceId(clientId);
        dto.setLetokenToken(token);
        dto.setUserId(userId);
        appUserImMQManager.imLoginUser(rabbitTemplate, dto);
    }


    @Override
    public AppUserLoginRes loginDev(AppUserLoginReq req, String clientIP) {
//        String walletAddress = req.getWalletAddress();
//        AppUserLoginRes res = new AppUserLoginRes();
//
//        AppUser appUser = appUserManager.queryByWalletAddres(walletAddress);
//        String token = TokenUtil.generateToken();
//        if (ObjectUtils.isEmpty(appUser)) {
//            appUser = new AppUser();
//            //用户信息为空，创建用户并绑定
//            appUser.setWalletAddress(walletAddress);
//            //给钱包分配地址
//            AppUserAddress wallet = null;
//            try {
//                wallet = appUserAddressManager.createWallet();
//            } catch (Exception e) {
//                throw new RuntimeException(e);
//            }
//            appUser.setAddressId(wallet.getId());
//            appUser.setInviterId(0);
//            appUser.setInvitationCode(RandomUtil.getRandomNum());
//            appUser.setCreateTime(LocalDateTime.now());
//            // todo token不入库
//            Integer flag = appUserManager.addUser(appUser);
//
//            if (flag > 0) {
//
//                // 写入当前用户token
//                AppUserTokenRedis.me().put(appUser.getId().toString(), token);
//
//                appUser.setUserName(LetokenUserConstant.USER_ID_PREFIX + appUser.getId());
//                appUser.updateById();
//                wallet.setUserId(appUser.getId());
//                wallet.updateById();
//                LocalDateTime now = LocalDateTime.now();
//                //将用户的平台钱包地址缓存到redis
//                AppWalletAddresRedis.me().put(String.valueOf(appUser.getId()), wallet.getWalletAddress());
//                AppUserTeam appUserTeam = new AppUserTeam();
//                appUserTeam.setUserId(appUser.getId());
//                appUserTeam.setEcoLevel(0);
//                appUserTeam.setEcoValue(BigDecimal.ZERO);
//                appUserTeam.setUserValue(BigDecimal.ZERO);
//                appUserTeam.setTeamMember(0);
//                appUserTeam.setTeamValue(0);
//                appUserTeam.setUserAchievement(0);
//                appUserTeam.setInviterId(0);
//                appUserTeam.setCreateTime(now);
//                appUserTeam.setUpdateTime(now);
//                appUserTeam.setTeamSumValue(0);
//                appUserTeam.insert();
//
//                AppUserTeamPath appUserTeamPath = new AppUserTeamPath();
//                appUserTeamPath.setUserId(appUser.getId());
//                appUserTeamPath.setInvitePath("");
//                appUserTeamPath.insert();
//
//
//                // 新增到资产表里
//                AppUserWallet letWallet = new AppUserWallet();
//                letWallet.setUserId(appUser.getId());
//                letWallet.setTokenId(LetokenTokenTypeEnum.LET.getId());
//                letWallet.setAvailableBalance(BigDecimal.ZERO);
//                letWallet.setFreezeBalance(BigDecimal.ZERO);
//                letWallet.setReleasedBalance(BigDecimal.ZERO);
//                letWallet.setUpdateTime(now);
//                letWallet.setCreateTime(now);
//
//                AppUserWallet usdtWallet = new AppUserWallet();
//                usdtWallet.setUserId(appUser.getId());
//                usdtWallet.setTokenId(LetokenTokenTypeEnum.USDT.getId());
//                usdtWallet.setAvailableBalance(BigDecimal.ZERO);
//                usdtWallet.setFreezeBalance(BigDecimal.ZERO);
//                usdtWallet.setReleasedBalance(BigDecimal.ZERO);
//                usdtWallet.setUpdateTime(now);
//                usdtWallet.setCreateTime(now);
//                List<AppUserWallet> walletList = new ArrayList<>();
//                walletList.add(letWallet);
//                walletList.add(usdtWallet);
//                appUserWalletService.saveBatch(walletList);
//            }
//            else {
//                throw new ApiServiceException(LetokenApiResponseEnum.ERROR_WALLET_WITHDRAW_015);
//            }
//        }
//        else {
//            //判断token是否存在缓存中，若存在，则踢出
//            String queryToken = AppUserTokenRedis.me().getValue(appUser.getId().toString());// appUser.getToken();
//            if (StringUtils.isNotBlank(queryToken)) {
//                AppLoginTokenRedis.me().del(queryToken);
//            }
//
//            // 更新当前用户token
//            AppUserTokenRedis.me().put(appUser.getId().toString(), token);
//        }
//
//        // token > 用户基础信息写入缓存
//        AppLoginTokenRedis.me().put(token, appUser);
//
//        // 用户登录将日志写入redis
//        this.lPushRedisLoginLog(appUser, req, clientIP);
//
//        //更新用户最后一次登录时间
//        appUserManager.updateById(appUser);
//
//        res.setToken(token);
//        String address = addressManager.queryWalletByUserId(appUser.getId());
//        res.setAppUserAddress(address);
//        return res;
        return new AppUserLoginRes();
    }
}
